<template>
  <article>
    <div class="top flex-box">
      <section class="flex-box month">
        <p class="title">月份</p>
        <el-date-picker
          :clearable="false"
          v-model="activeStartDate"
          type="month"
          placeholder="选择月份"
          @change="handleMonthChange"
        />
      </section>
      <section>
        <el-button type="primary" class="ml10" @click="changeMonth(0)">
          本月
        </el-button>  
        <el-button-group>
          <el-button type="primary" class="ml10" @click="changeMonth(-1)">
            上月
          </el-button>
          <el-button type="primary" class="" @click="changeMonth(1)">下月</el-button>
        </el-button-group>
      </section>
    </div>

    <div ref="dateHeader" class="line-header">
      <div
        v-for="item in columns"
        :key="item.prop"
        class="item-header"
      >
        {{ item.label }}
      </div>
    </div>
    <div
      v-for="(dateRow, i) in dateGroupList"
      :key="i"
      :class="['line', { 'last-line': i === 5 }]"
    >
      <div
        v-for="(date, j) in dateRow"
        :key="date.value"
        :class="[
          'item',
          getCellClass(date),
        ]"
        @click="handleClickCell(date.value)"
      >
        <span :class="['day', { 'not-this-month': !date.isSameMonth }]">{{
          date.label
        }}</span>
        <slot :date="date.value"></slot>
      </div>
    </div>
  </article>
</template>

<script lang="ts">
export default {
  name: "ChooseDate",
};
</script>
<script lang="ts" setup>
import {
  getDay,
  subDays,
  subWeeks,
  format,
  addDays,
  isSunday,
  isToday,
  isSameMonth,
  addMonths,
  setDate,
} from "date-fns";

const props = defineProps({
  // 类型,可选值: ''/'daterange'
  type: {
    type: String,
    default: "date",  
  },
  value: {
    type: [String, Array],
    default: "",
  },
})
// 点击单元格事件；告知父组件当前的起止日期；
const emit = defineEmits(["month-change", "cell-click", "update:value"]);

const columns = ref([
  {
    label: '周日',
    prop: 'sunday',
  },
  {
    label: '周一',
    prop: 'monday',
  },
  {
    label: '周二',
    prop: 'tuesday',
  },
  {
    label: '周三',
    prop: 'wednesday',   
  },
  {
    label: '周四',
    prop: 'thursday',
  },
  {
    label: '周五',
    prop: 'friday',
  },
  {
    label: '周六',
    prop: 'saturday',
  },
]);

/**
 * 获取当前月
 * 获取当前月1日
 * 获取当前月1日所在行的周日(或周一)，作为第一个格子
 * 然后加够6行共计42天
 */
const activeStartDate = ref(new Date());
const firstDayOfMonthNow = computed(() => setDate(activeStartDate.value, 1));

// 计算日期格子中需要的数据
const formatDate = (date: Date) => {
  return {
    value: format(date, "yyyy-MM-dd"),
    label: format(date, "MM月dd日"),
    isToday: isToday(date),
    isSameMonth: isSameMonth(date, firstDayOfMonthNow.value),
  };
};

const dateGroupList = computed(() => {
  // 获得第一个格子
  let firstCell;
  if (isSunday(firstDayOfMonthNow.value)) {
    // 如果当天是周日的话，调用这个方法会再往前倒一周
    firstCell = subWeeks(firstDayOfMonthNow.value, 1);
  } else {
    // 获取当前月1日是星期几，周日返回0,周一到周六返回1到6
    const firstDayOfWeek = getDay(firstDayOfMonthNow.value)
    firstCell = subDays(firstDayOfMonthNow.value, firstDayOfWeek);
  }
  const firstCellValue = formatDate(firstCell);
  const temp = [[firstCellValue], [], [], [], [], []];
  let j = 0;
  // 从1开始计数，因为第一个格子已经存入
  for (let i = 1; i < 42; i++) {
    // 每够7天，就开始二维数组的下一行
    if (i % 7 === 0) {
      j++;
    }
    const date = formatDate(addDays(firstCell, i));
    temp[j].push(date);
  }

  return temp;
});

const sendStartEnd = () => {
  const start = dateGroupList.value[0][0].value;
  const end = dateGroupList.value[5][6].value;
  emit("month-change", { start, end });
};

// 月份选择器触发回调
const handleMonthChange = (e: Date) => {
  activeStartDate.value = e;
  sendStartEnd();
};

const changeMonth = (num: number) => {
  if (num === 0) {
    activeStartDate.value = new Date();
  } else {
    activeStartDate.value = addMonths(activeStartDate.value, num);
  }
  sendStartEnd();
};


const selectedCell = ref("");
const selectedRangeValue = ref<string[]>([]) 
// 点击单元格触发回调
const handleClickCell = (dateValue: string) => {
  selectedCell.value = dateValue;
  let newValue: string | string[] = dateValue;
  if (props.type === 'daterange') {
    const len = unref(selectedRangeValue).length
    if (len === 0) {
      selectedRangeValue.value.push(dateValue);
    } else if (len === 1) {
      selectedRangeValue.value.push(dateValue);
      selectedRangeValue.value = selectedRangeValue.value.sort((a, b) => new Date(a).getTime() - new Date(b).getTime());
    } else if (len === 2) {
      selectedRangeValue.value = [];
      selectedRangeValue.value[0] = dateValue;
    }
    newValue = selectedRangeValue.value;
  }
  emit("cell-click", dateValue);
  emit("update:value", newValue);
};
const getCellClass = computed(() => {
  return (date: any) => {
    const today = date.isToday;
    const current = selectedCell.value === date.value;
    const startDate = selectedRangeValue.value[0] === date.value;
    const endDate = selectedRangeValue.value[1] === date.value;
    const startTimeStamp = new Date(selectedRangeValue.value[0]).getTime();
    const endTimeStamp = new Date(selectedRangeValue.value[1]).getTime();
    const inRange = startTimeStamp < new Date(date.value).getTime() && endTimeStamp > new Date(date.value).getTime()
    return {
      today,
      current,
      'start-date': startDate,
      'end-date': endDate,
      'in-range': inRange,
    }
  }
})

const initSelectedValue = () => {
  if (typeof props.value === 'string') {
    selectedCell.value = props.value;
  }
  if (Array.isArray(props.value)) {
    selectedRangeValue.value = props.value as string[]
  }
}
const init = () => {
  initSelectedValue()
  sendStartEnd()
}

onMounted(init);
</script>

<style lang="scss" scoped>
$hight-light-color: #409eff;
.flex-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.ml10 {
  margin-left: 10px;
}

.top {
  margin-bottom: 15px;
  .title {
    margin-right: 10px;
  }
}
.month :deep(.el-input__inner) {
  font-size: 16px;
  // font-weight: bolder;
}
.line-header {
  display: flex;
  align-items: center;
  justify-content: space-around;
  .item-header {
    position: relative;
    flex: 1;
    height: 60px;
    line-height: 60px;
    border: 1px solid #ddd;
    border-right-color: transparent;
    border-bottom-color: transparent;
  
    text-align: center;
    font-weight: bolder;
    background-color: $hight-light-color;
    color: #ffffff;
  }
}

.line {
  display: flex;
  align-items: center;
  justify-content: space-around;
  .item {
    position: relative;
    flex: 1;
    // width: 100px;
    height: 100px;
    border: 1px solid #ddd;
    border-right-color: transparent;
    border-bottom-color: transparent;
    cursor: pointer;
    &:last-child {
      border-right: 1px solid #ddd;
    }
    &:hover {
      box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.12);
      border-radius: 4px;
    }
    .day {
      position: absolute;
      right: 5px;
      top: 5px;
    }
    .not-this-month {
      opacity: 0.3;
    }
  }
  .today {
    color: $hight-light-color;
  }
  .current {
    background-color: $hight-light-color;
    color: #ffffff;
    box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.12);
    border-radius: 4px;
  }
  .in-range {
    background-color: #f2f6fc;
  }
  .start-date, .end-date {
    background-color: $hight-light-color;
    color: #ffffff;
    box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.12);
    border-radius: 4px;
  }
}
.last-line .item {
  border-bottom: 1px solid #ddd;
}
</style>
